import { createSlice, createAsyncThunk, PayloadAction } from '@reduxjs/toolkit';
import axios from 'axios';
import { setLoading } from './uiSlice';

// Types
interface TestCase {
  input: string;
  expectedOutput: string;
  description: string;
}

interface Challenge {
  _id: string;
  title: string;
  description: string;
  pattern: {
    _id: string;
    name: string;
    category: string;
  };
  level: 'beginner' | 'intermediate' | 'advanced';
  scenario: string;
  requirements: string[];
  hints: string[];
  testCases: TestCase[];
  timeLimit: number;
  difficulty: number;
  tags: string[];
}

interface Evaluation {
  rating: 'Unsatisfactory' | 'Satisfactory' | 'Good' | 'Excellent';
  feedback: string;
  suggestions: string;
  correctPatternUsage: boolean;
}

interface SubmissionResult {
  evaluation: Evaluation;
  progress: {
    completed: boolean;
    attempts: number;
    rating: string;
  };
}

interface ChallengeState {
  challenges: Challenge[];
  currentChallenge: Challenge | null;
  userSolution: string;
  submissionResult: SubmissionResult | null;
  loading: boolean;
  error: string | null;
}

const initialState: ChallengeState = {
  challenges: [],
  currentChallenge: null,
  userSolution: '',
  submissionResult: null,
  loading: false,
  error: null
};

// Get challenges by pattern ID
export const getChallengesByPattern = createAsyncThunk(
  'challenges/getChallengesByPattern',
  async (patternId: string, { dispatch, rejectWithValue }) => {
    try {
      dispatch(setLoading({ key: 'challenges', value: true }));
      
      const token = localStorage.getItem('token');
      
      if (!token) {
        return rejectWithValue('No token');
      }
      
      const config = {
        headers: {
          'x-auth-token': token
        }
      };
      
      const res = await axios.get(`/api/challenges/pattern/${patternId}`, config);
      
      dispatch(setLoading({ key: 'challenges', value: false }));
      return res.data;
    } catch (err: any) {
      dispatch(setLoading({ key: 'challenges', value: false }));
      return rejectWithValue(err.response?.data?.msg || 'Server Error');
    }
  }
);

// Get challenge by ID
export const getChallengeById = createAsyncThunk(
  'challenges/getChallengeById',
  async (challengeId: string, { dispatch, rejectWithValue }) => {
    try {
      dispatch(setLoading({ key: 'challenges', value: true }));
      
      const token = localStorage.getItem('token');
      
      if (!token) {
        return rejectWithValue('No token');
      }
      
      const config = {
        headers: {
          'x-auth-token': token
        }
      };
      
      const res = await axios.get(`/api/challenges/${challengeId}`, config);
      
      dispatch(setLoading({ key: 'challenges', value: false }));
      return res.data;
    } catch (err: any) {
      dispatch(setLoading({ key: 'challenges', value: false }));
      return rejectWithValue(err.response?.data?.msg || 'Server Error');
    }
  }
);

// Submit solution
export const submitSolution = createAsyncThunk(
  'challenges/submitSolution',
  async ({ challengeId, solution }: { challengeId: string; solution: string }, { dispatch, rejectWithValue }) => {
    try {
      dispatch(setLoading({ key: 'submission', value: true }));
      
      const token = localStorage.getItem('token');
      
      if (!token) {
        return rejectWithValue('No token');
      }
      
      const config = {
        headers: {
          'Content-Type': 'application/json',
          'x-auth-token': token
        }
      };
      
      const res = await axios.post(`/api/challenges/${challengeId}/submit`, { solution }, config);
      
      dispatch(setLoading({ key: 'submission', value: false }));
      return res.data;
    } catch (err: any) {
      dispatch(setLoading({ key: 'submission', value: false }));
      
      // Enhanced error handling
      if (err.response) {
        // The request was made and the server responded with a status code
        // that falls out of the range of 2xx
        const errorData = err.response.data;
        if (errorData && errorData.error) {
          console.error('API Error Details:', errorData.error);
          return rejectWithValue({
            msg: errorData.msg || 'Server Error',
            details: errorData.error
          });
        }
        return rejectWithValue(errorData.msg || 'Server Error');
      } else if (err.request) {
        // The request was made but no response was received
        console.error('No response received:', err.request);
        return rejectWithValue('No response from server. Please check your connection.');
      } else {
        // Something happened in setting up the request that triggered an Error
        console.error('Request setup error:', err.message);
        return rejectWithValue(err.message || 'Request failed');
      }
    }
  }
);

const challengeSlice = createSlice({
  name: 'challenges',
  initialState,
  reducers: {
    updateUserSolution: (state, action: PayloadAction<string>) => {
      state.userSolution = action.payload;
    },
    clearCurrentChallenge: (state) => {
      state.currentChallenge = null;
      state.userSolution = '';
      state.submissionResult = null;
    },
    clearSubmissionResult: (state) => {
      state.submissionResult = null;
    },
    clearChallengeError: (state) => {
      state.error = null;
    }
  },
  extraReducers: (builder) => {
    builder
      // Get challenges by pattern ID
      .addCase(getChallengesByPattern.pending, (state) => {
        state.loading = true;
      })
      .addCase(getChallengesByPattern.fulfilled, (state, action: PayloadAction<Challenge[]>) => {
        state.loading = false;
        state.challenges = action.payload;
      })
      .addCase(getChallengesByPattern.rejected, (state, action) => {
        state.loading = false;
        state.error = action.payload as string;
      })
      // Get challenge by ID
      .addCase(getChallengeById.pending, (state) => {
        state.loading = true;
      })
      .addCase(getChallengeById.fulfilled, (state, action: PayloadAction<Challenge>) => {
        state.loading = false;
        state.currentChallenge = action.payload;
        state.userSolution = ''; // Reset user solution when loading a new challenge
        state.submissionResult = null; // Reset submission result
      })
      .addCase(getChallengeById.rejected, (state, action) => {
        state.loading = false;
        state.error = action.payload as string;
      })
      // Submit solution
      .addCase(submitSolution.pending, (state) => {
        state.loading = true;
      })
      .addCase(submitSolution.fulfilled, (state, action: PayloadAction<SubmissionResult>) => {
        state.loading = false;
        state.submissionResult = action.payload;
      })
      .addCase(submitSolution.rejected, (state, action) => {
        state.loading = false;
        state.error = action.payload as string;
      });
  }
});

export const {
  updateUserSolution,
  clearCurrentChallenge,
  clearSubmissionResult,
  clearChallengeError
} = challengeSlice.actions;

export default challengeSlice.reducer; 